#include "Socket.hpp"
#include "Log.hpp"
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <poll.h>

static const uint16_t defaultport = 8888;
static const int fd_num_max = 64;
int defaultfd = -1;
int non_event = 0;

class pollServer
{
public:
    pollServer(const uint16_t _port = defaultport) : port(_port)
    {
        for (int i = 0; i < fd_num_max; i++)
        {
            _event_fd[i].fd = defaultfd;
            _event_fd[i].events = non_event;
            _event_fd[i].revents = non_event;
        }
    }

    void Init()
    {
        _listensockfd.Socket();
        _listensockfd.Bind(port);
        _listensockfd.Listen();
        std::cout << "success Init" << std::endl;
    }

    void start()
    {
        _event_fd[0].fd = _listensockfd.Getfd();
        _event_fd[0].events = POLLIN; // 从全连接队列中获取数据，也是等待资源，本身也是读的一种

        int timeout = 3000; //单位：毫秒
        for (;;)
        {
            std::cout << sizeof(_event_fd) << std::endl;
            int n = poll(_event_fd, fd_num_max, timeout);
            switch (n)
            {
            case 0:
                break; // 超时，没有文件描述符就绪
            case -1:
                std::cout << "select error" << std::endl;
                break;
            default:
                // cout << "get a new link!!!!!" << endl;
                Dispatcher(); // 对就绪事件进行派发
                break;
            }
        }
    }

    void Dispatcher() // 事件分配器
    {
        for (int i = 0; i < fd_num_max; i++)
        {
            int fd = _event_fd[i].fd;
            if (fd == defaultfd)
                continue;
            if (_event_fd[i].revents & POLLIN) // 成立，代表文件描述符就绪
            {
                if (_listensockfd.Getfd() == fd)
                {
                    Accepter();
                }
                else
                {
                    Recver(fd, i);
                }
            }
        }
    }

    void Accepter()
    {
        std::string clientip;
        uint16_t clientport = 0;
        int sock = _listensockfd.Accept(clientip, clientport);
        lg(INFO, "accept success, %s %d", clientip.c_str(), clientport);

        int pos = 1;
        for (; pos < fd_num_max; pos++)
        {
            if (_event_fd[pos].fd != defaultfd)
                continue;
            break;
        }

        // 判断fd_array是否为满, 满则关闭该文件描述符，否则添加到数组fd_array中
        if (pos == fd_num_max)
        {
            lg(WARNING, "server full!, now close %d", sock);
            close(sock);
        }
        else
        {
            _event_fd[pos].fd = sock;
            _event_fd[pos].events = POLLIN;
            Printfd();
        }
    }

    void Recver(int fd, int pos)
    {
        char buffer[1024];
        int n = recv(fd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << "get a massage: " << buffer << std::endl;
        }
        else if (n == 0) // 缓冲区中已经没有数据，此时应该关闭文件，并更新fd_array数组
        {
            lg(INFO, "client quit, close fd: %d", fd);
            close(fd);
            _event_fd[pos].fd = defaultfd;
        }
        else
        {
            lg(ERROR, "read error, fd is %d", fd);
            close(fd);
            _event_fd[pos].fd = defaultfd;
        }
    }

    void Printfd()
    {
        for (int i = 0; i < fd_num_max; i++)
        {
            if (_event_fd[i].fd != defaultfd)
            {
                std::cout << _event_fd[i].fd << " ";
            }
        }
        std::cout << "\n";
    }

    ~pollServer() {}

private:
    Sock _listensockfd;
    uint16_t port;
    struct pollfd _event_fd[fd_num_max];
};
